home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #9 / Amiga Plus CD - 2004 - No. 09.iso / amigaplus / tools / amigaos4_only / fracblank / source / fracblanker.c < prev    next >
C/C++ Source or Header  |  2004-08-03  |  14KB  |  552 lines

  1. /*
  2. **  FracBlank - AmigaDOS 2.04 commodities utility screenblanker
  3. **
  4. **  Copyright © 1991-1995 by Olaf `Olsen' Barthel
  5. **    All Rights Reserved
  6. **
  7. **  Cosmic flame fractal code derived from xlock source code
  8. **
  9. **  Copyright © 1988-1991 by Patrick J. Naughton.
  10. */
  11.  
  12. #include <math.h>
  13.  
  14. #include <clib/alib_protos.h>
  15.  
  16. #include <dos/dos.h>
  17.  
  18. #include <proto/dos.h>
  19. #include <proto/exec.h>
  20. #include <proto/graphics.h>
  21.  
  22. #include "Frac.h"
  23. #include "FracBlanker.h"
  24.  
  25. // Spread a byte across a long word
  26.  
  27. #define SPREAD(v) ((ULONG)(v) << 24 | (ULONG)(v) << 16 | (ULONG)(v) << 8 | (v))
  28.  
  29. // BlankerEntry data
  30.  
  31. ULONG CycleMask;
  32. LONG  CycleBit;
  33.  
  34. // sin -45° = cos -45° (saves precious calculation time)
  35.  
  36. double deg45;
  37.  
  38. // The current fractal type
  39.  
  40. UBYTE FractalType;
  41.  
  42. // Screen and pattern change timeout
  43.  
  44. ULONG ScreenCount    = 0,
  45.       PatternCount   = 0,
  46.       ScreenTimeout  = 60,
  47.       PatternTimeout = 60;
  48.  
  49. // Declarations for cosmic flame blanker code
  50.  
  51. double Flame[2][3][2];
  52. WORD   FlameLevel,
  53.        FlameAlternateForm;
  54. WORD   FlameWheel,
  55.        FlameColour;
  56. ULONG  FlamePoints;
  57. ULONG  MaxRecursionLevel = 40,
  58.        MaxFlamePoints    = 200;
  59.  
  60. // Prototypes
  61.  
  62. VOID CosmicFlame();
  63. BOOL RecurseMono(double x, double y, WORD Level);
  64. BOOL RecurseColour(double x, double y, WORD Level);
  65. VOID RealPlane();
  66. ULONG Random(ULONG MaxValue);
  67. VOID MonoPlot(WORD Left, WORD Top);
  68. VOID MultiPlot(ULONG Colour, WORD Left, WORD Top);
  69. VOID BlackScreen();
  70. VOID RotatePalette();
  71.  
  72. /* BlankerEntry():
  73.  *
  74.  *  The screen blanker itself.
  75.  */
  76.  
  77. VOID BlankerEntry() {
  78.  
  79. //LONG CycleBit;
  80.  
  81.   IExec->Forbid();
  82.  
  83.   // Shouldn't go wrong right now, this is the second
  84.   // action this task takes, about 16 signal bits
  85.   // should still be vacant
  86.  
  87.   if ((CycleBit = IExec->AllocSignal(-1)) != -1) {
  88.     CycleMask = (1L << CycleBit);
  89.     // Tell the control process we're running
  90.     IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  91.     // Now step back
  92.     IExec->SetTaskPri(SysBase->ThisTask,-20);
  93.     IExec->Permit();
  94.     // Determine the fractal type
  95.     if (FractalType == FRACTAL_COSMIC_FLAME) CosmicFlame();
  96.     else {
  97.       if (FractalType == FRACTAL_REAL_PLANE) RealPlane();
  98.       else {
  99.         if (Random(42) >= 21) CosmicFlame();
  100.         else RealPlane();
  101.       }
  102.     }
  103.   }
  104.   else {
  105.     // Wave goodbye
  106.     BlankTask = NULL;
  107.     IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  108.   }
  109.  
  110. }
  111.  
  112. /* CosmicFlame():
  113.  *
  114.  *  The cosmic flame screen blanker.
  115.  *
  116.  *  xlock.c - X11 client to lock a display and show a screen saver.
  117.  *
  118.  *  Copyright (c) 1988-91 by Patrick J. Naughton.
  119.  *
  120.  *  Permission to use, copy, modify, and distribute this software and its
  121.  *  documentation for any purpose and without fee is hereby granted,
  122.  *  provided that the above copyright notice appear in all copies and that
  123.  *  both that copyright notice and this permission notice appear in
  124.  *  supporting documentation.
  125.  */
  126.  
  127. VOID CosmicFlame() {
  128.  
  129.   WORD i,
  130.        j,
  131.        k;
  132.  
  133.   BOOL Alternate = FALSE;
  134.  
  135.   FlameLevel = 0;
  136.  
  137.   // Monochrome mode?
  138.  
  139.   if (DisplayDepth == 1) {
  140.     // Go into fractal generation loop
  141.     for(;;) {
  142.       if (!((FlameLevel++) % MaxRecursionLevel)) {
  143.         BlackScreen();
  144.         Alternate = !Alternate;
  145.       }
  146.       if (Alternate) FlameAlternateForm = 0;
  147.       else FlameAlternateForm = Random(2) + 2;
  148.       for(k = 0; k < 2; k++) {
  149.         for(i = 0; i < 2; i++) {
  150.           for(j = 0; j < 3; j++) Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
  151.         }
  152.       }
  153.       FlamePoints = 0;
  154.       RecurseMono(0.0,0.0,0);
  155.     }
  156.   }
  157.   else {
  158.     FlameColour = Random(MaxColour - 1) + 1;
  159.     for(;;) {
  160.       if (!((FlameLevel++) % MaxRecursionLevel)) {
  161.         BlackScreen();
  162.         Alternate = !Alternate;
  163.       }
  164.       else {
  165.         WORD NewColour;
  166.         do NewColour = Random(MaxColour - 1) + 1;
  167.         while(NewColour == FlameColour);
  168.         FlameColour = NewColour;
  169.       }
  170.       if (Alternate) FlameAlternateForm = 0;
  171.       else FlameAlternateForm = Random(2) + 2;
  172.       for(k = 0; k < 2; k++) {
  173.         for(i = 0; i < 2; i++) {
  174.           for(j = 0; j < 3; j++) Flame[i][j][k] = ((double)Random(1024)) / 512.0 - 1.0;
  175.         }
  176.       }
  177.       FlamePoints = 0;
  178.       RecurseColour(0.0,0.0,0);
  179.     }
  180.   }
  181.  
  182. }
  183.  
  184. /* RecurseMono(double x,double y,WORD Level):
  185.  *
  186.  *  Cosmic flame calculation routine (monochrome).
  187.  */
  188.  
  189. BOOL RecurseMono(double x, double y, WORD Level) {
  190.  
  191.   ULONG Signals = IExec->SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  192.  
  193.   // Are we to shut down?
  194.  
  195.   if (Signals & SIG_BREAK) {
  196.     IExec->Forbid();
  197.     IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  198.     IExec->FreeSignal(CycleBit);
  199.     IExec->RemTask(NULL);
  200.   }
  201.  
  202.   // Return to top level?
  203.  
  204.   if (StopDrawing) {
  205.     FlameLevel  = 0;
  206.     StopDrawing  = FALSE;
  207.     return(FALSE);
  208.   }
  209.  
  210.   // Change the pattern?
  211.  
  212.   if (Signals & SIG_CHANGE) {
  213.     FlameLevel  = 0;
  214.     StopDrawing  = FALSE;
  215.     return(FALSE);
  216.   }
  217.  
  218.   // Cycle the colours?
  219.  
  220.   if (Signals & CycleMask) {
  221.     IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  222.     Wheel = (Wheel + 1) % MaxColour;
  223.     RotatePalette();
  224.   }
  225.  
  226.   if (Level >= MaxRecursionLevel) {
  227.     if ((FlamePoints++) > MaxFlamePoints * 100) return(FALSE);
  228.     else MonoPlot((WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
  229.   }
  230.   else {
  231.     double nx,ny;
  232.     WORD   i;
  233.     for(i = 0; i < 2; i++) {
  234.       nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
  235.       ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
  236.       if (i < FlameAlternateForm) {
  237.         nx = sin(nx);
  238.         ny = sin(ny);
  239.       }
  240.       if (!StopDrawing) {
  241.         if (!RecurseMono(nx,ny,Level + 1)) return(FALSE);
  242.       }
  243.       else return(FALSE);
  244.     }
  245.   }
  246.  
  247.   return(TRUE);
  248.  
  249. }
  250.  
  251. /* RecurseColour(double x,double y,WORD Level):
  252.  *
  253.  *  Cosmic flame calculation routine (colour).
  254.  */
  255.  
  256. BOOL RecurseColour(double x, double y, WORD Level) {
  257.  
  258.   ULONG Signals = IExec->SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  259.  
  260.   if (Signals & SIG_BREAK) {
  261.     IExec->Forbid();
  262.     IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  263.     IExec->FreeSignal(CycleBit);
  264.     IExec->RemTask(NULL);
  265.   }
  266.  
  267.   if (StopDrawing) {
  268.     FlameLevel  = 0;
  269.     StopDrawing  = FALSE;
  270.     return(FALSE);
  271.   }
  272.  
  273.   /* Change the pattern? */
  274.  
  275.   if (Signals & SIG_CHANGE) {
  276.     FlameLevel  = 0;
  277.     StopDrawing  = FALSE;
  278.     return(FALSE);
  279.   }
  280.  
  281.   // Cycle the colours?
  282.  
  283.   if (Signals & CycleMask) {
  284.     IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  285.     Wheel = (Wheel + 1) % MaxColour;
  286.     RotatePalette();
  287.   }
  288.  
  289.   if (Level >= MaxRecursionLevel) {
  290.     if ((FlamePoints++) > MaxFlamePoints * 100) return(FALSE);
  291.     else MultiPlot(FlameColour,(WORD)((Width / 2) * (x + 1.0)),(WORD)((Height / 2) * VerticalScale * (y + 1.0)));
  292.   }
  293.   else {
  294.     double nx,ny;
  295.     WORD   i;
  296.     for(i = 0; i < 2; i++) {
  297.       nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i];
  298.       ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i];
  299.       if (i < FlameAlternateForm) {
  300.         nx = sin(nx);
  301.         ny = sin(ny);
  302. //      nx = atan(ny / nx) / 3.14159;
  303. //      ny = sqrt(pow(nx,2.0) + pow(ny,2.0)) - 1.0;
  304.       }
  305.       if (!StopDrawing) {
  306.         if (!RecurseColour(nx,ny,Level + 1)) return(FALSE);
  307.       }
  308.       else return(FALSE);
  309.     }
  310.   }
  311.  
  312.   return(TRUE);
  313.  
  314. }
  315.  
  316. /* RealPlane():
  317.  *
  318.  *  Draw real plane fractals.
  319.  */
  320.  
  321. VOID RealPlane() {
  322.  
  323.   UWORD  OffsetX = Width / 2,OffsetY = Height / 2;
  324.   ULONG  Signals;
  325.   double x = 0,y = 0,yy,a,b,c,sx,sy,mag;
  326.  
  327.   // Are we running in monochrome mode?
  328.  
  329.   if (DisplayDepth == 1) {
  330.     // Provide starting numbers for the fractal
  331.     // parameters
  332.     a = (double)(Random(700) + 5) / 100;
  333.     b = (double)(Random(190) + 5) / 100;
  334.     c = (double)(Random( 90) + 5) / 100;
  335.     mag = (double)(1 << (Random(6) + 2)) * deg45;
  336.     // Go into fractal generation loop
  337.     for(;;) {
  338.       Signals = IExec->SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  339.       // Are we to shut down?
  340.       if (Signals & SIG_BREAK) {
  341.         IExec->Forbid();
  342.         IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  343.         IExec->FreeSignal(CycleBit);
  344.         IExec->RemTask(NULL);
  345.       }
  346.       /* The original formula looks like
  347.        * this:
  348.        *                                    ½
  349.        *    x = y - SIGN(x) × ABS(b × x - c)
  350.        *    y = a - x
  351.        *
  352.        * I have split the calculation into
  353.        * several steps to save time and
  354.        * variables.
  355.        */
  356.       yy = a - x;
  357.       if (x < 0) x = y + sqrt(fabs(b * x - c));
  358.       else x = y - sqrt(fabs(b * x - c));
  359.       y = yy;
  360.       /* The resulting image appears to have
  361.        * been rotated by 45°, so we'll
  362.        * rotate the pixel coordinates by -45°
  363.        *
  364.        *    x =  x × cos(alpha) + y × sin(alpha)
  365.        *    y = -x × sin(alpha) + y × cos(alpha)
  366.        *
  367.        * We also magnify the image (i.e. the
  368.        * distribution of pixels) in the following
  369.        * lines.
  370.        */
  371.       sx = mag *                 ( x + y);
  372.       sy = mag * VerticalScale * (-x + y);
  373.       // If the pixel happens to reside within
  374.       // the boundaries of the screen, draw it.
  375.       MonoPlot((WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
  376.       // Change the pattern?
  377.       if (Signals & SIG_CHANGE) {
  378.         BlackScreen();
  379.         StopDrawing = FALSE;
  380.         x = y = 0;
  381.         a = (double)(Random(700) + 5) / 100;
  382.         b = (double)(Random(190) + 5) / 100;
  383.         c = (double)(Random( 90) + 5) / 100;
  384.         mag = (double)(1 << (Random(6) + 2)) * deg45;
  385.         Signals &= ~CycleMask;
  386.       }
  387.       // Cycle the colours?
  388.       if (Signals & CycleMask) {
  389.         IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  390.         Wheel = (Wheel + 1) % MaxColour;
  391.         RotatePalette();
  392.       }
  393.     }
  394.   }
  395.   else {
  396.     UWORD Count = 0;
  397.     WORD  Colour;
  398.     a = (double)(Random(700) + 5) / 100;
  399.     b = (double)(Random(190) + 5) / 100;
  400.     c = (double)(Random( 90) + 5) / 100;
  401.     mag = (double)(1 << (Random(6) + 2)) * deg45;
  402.     Colour = Random(MaxColour - 1) + 1;
  403.     for(;;) {
  404.       Signals = IExec->SetSignal(0,SIG_BREAK | SIG_CHANGE | CycleMask);
  405.       if (Signals & SIG_BREAK) {
  406.         IExec->Forbid();
  407.         IExec->Signal((struct Task *)BlankerControlProcess,SIG_HANDSHAKE);
  408.         IExec->FreeSignal(CycleBit);
  409.         IExec->RemTask(NULL);
  410.       }
  411.       yy = a - x;
  412.       if (x < 0) x = y + sqrt(fabs(b * x - c));
  413.       else x = y - sqrt(fabs(b * x - c));
  414.       y = yy;
  415.       sx = mag *                 ( x + y);
  416.       sy = mag * VerticalScale * (-x + y);
  417.       MultiPlot(Colour,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY);
  418.       /* Oh well, it's not that easy to
  419.        * produce decent colour values for
  420.        * the pixels to be rendered.
  421.        *
  422.        * The following statement will change
  423.        * the current drawing pen after exactly
  424.        * 1200 pixels have been rendered and will
  425.        * pick a new colour between 1 and 31.
  426.        */
  427.       if (Count++ >= 1200) {
  428.         WORD NewColour;
  429.         Count = 0;
  430.         do NewColour = Random(MaxColour - 1) + 1;
  431.         while(NewColour == Colour);
  432.         Colour = NewColour;
  433.       }
  434.       if (Signals & SIG_CHANGE) {
  435.         BlackScreen();
  436.         StopDrawing = FALSE;
  437.         x = y = 0;
  438.         a = (double)(Random(700) + 5) / 100;
  439.         b = (double)(Random(190) + 5) / 100;
  440.         c = (double)(Random( 90) + 5) / 100;
  441.         mag = (double)(1 << (Random(6) + 2)) * deg45;
  442.         Signals &= ~CycleMask;
  443.       }
  444.       if (Signals & CycleMask) {
  445.         IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  446.         Wheel = (Wheel + 1) % MaxColour;
  447.         RotatePalette();
  448.       }
  449.     }
  450.   }
  451.  
  452. }
  453.  
  454. /* Random(ULONG MaxValue):
  455.  *
  456.  *  Simple random number generation routine.
  457.  */
  458.  
  459. ULONG Random(ULONG MaxValue) {
  460.   
  461.   struct DateStamp ds;
  462.   
  463.   IDOS->DateStamp(&ds);
  464.   
  465.   if (MaxValue) {
  466.     static ULONG RandomSeed = 3735879991UL;
  467.     RandomSeed = RandomSeed * (((ULONG)ds.ds_Minute) * ((ULONG)ds.ds_Tick)) + 3780343439UL;
  468.     RandomSeed = FastRand(RandomSeed);
  469.     return(RandomSeed % MaxValue);
  470.   }
  471.   else return(0);
  472.  
  473. }
  474.  
  475. /* MonoPlot(WORD Left,WORD Top):
  476.  *
  477.  *  Set a pixel somewhere on the screen.
  478.  */
  479.  
  480. VOID MonoPlot(WORD Left, WORD Top) {
  481.  
  482.   if (Left >= 0 && Left < Width && Top >= 0 && Top < Height) IGraphics->WritePixel(RPort,Left,Top);
  483.  
  484. }
  485.  
  486. /* MultiPlot(ULONG Colour,WORD Left,WORD Top):
  487.  *
  488.  *  Set a coloured pixel somewhere on the screen.
  489.  */
  490.  
  491. VOID MultiPlot(ULONG Colour, WORD Left, WORD Top) {
  492.  
  493.   if (Left >= 0 && Left < Width && Top >= 0 && Top < Height) {
  494.     if (Pen != Colour) IGraphics->SetAPen(RPort,Pen = Colour);
  495.     IGraphics->WritePixel(RPort,Left,Top);
  496.   }
  497.  
  498. }
  499.  
  500. /* BlackScreen():
  501.  *
  502.  *  Clear the screen, this is accomplished by first setting the
  503.  *  screen colours to black, clearing the screen and finally
  504.  *  restoring the palette.
  505.  */
  506.  
  507. VOID BlackScreen() {
  508.  
  509.   WORD Count;
  510.  
  511.   Count = Colours->NumColours;
  512.  
  513.   Colours->NumColours = MaxColour + 1;
  514.  
  515.   memset(&Colours->Entry[0],0,256 * sizeof(ColourEntry));
  516.  
  517.   IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  518.  
  519.   IGraphics->SetRast(RPort,0);
  520.  
  521.   Colours->NumColours = Count;
  522.  
  523.   RotatePalette();
  524.  
  525.   IGraphics->LoadRGB32(VPort,(ULONG *)Colours);
  526.  
  527. }
  528.  
  529. /* RotatePalette():
  530.  *
  531.  *  Fill in the screen palette with new data.
  532.  */
  533.  
  534. VOID RotatePalette() {
  535.  
  536.   WORD i,
  537.        Index = Wheel;
  538.  
  539.   for(i = 1; i <= MaxColour; i++)  {
  540.     Colours->Entry[i].Red   = SPREAD(Red[Index]);
  541.     Colours->Entry[i].Green = SPREAD(Green[Index]);
  542.     Colours->Entry[i].Blue  = SPREAD(Blue[Index]);
  543.     Index = (Index + 1) % MaxColour;
  544.   }
  545.  
  546.   // Terminate the table, just in case...
  547.  
  548.   Colours->Entry[Colours->NumColours].Red = 0;
  549.  
  550. }
  551.  
  552.